package tool

import java.io.File

import play.api.libs.json.Json
import tool.Pojo.CommandData
import implicits.Implicits._
import org.apache.commons.io.FileUtils
import utils.Utils

/**
 * Created by yz on 23/3/2020
 */
trait ProjectTool {

  def tcdb(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.vfdbForm.bind(configJson).get
    val seqFile = Tool.getSeqFile(workspaceDir)
    val blast = if (data.seqType == "n") Tool.blastxFile else Tool.blastpFile
    val task = if (data.seqType == "p") "blastp-fast" else "blastx-fast"
    val command =
      s"""
         |${blast.unixPath} -db ${Tool.annoDir.unixPath}/TCDB/tcdb.fasta -query ${seqFile.unixPath} -out data.xml -task ${task} -evalue ${data.evalue} -outfmt 5 -num_threads 4 -max_target_seqs ${data.maxTargetSeqs}
         |perl ${Tool.annoDir.unixPath}/anno_st/Blast2table -format 10 -xml data.xml -header -top >data.table.xls
         |cp data.table.xls ${resultDir.unixPath}/tcdb.anno.xls
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def pfam(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.pfamForm.bind(configJson).get
    val seqFile = Tool.getSeqFile(workspaceDir)
    val outFile = Tool.getPfamOutFile(workspaceDir)
    val command =
      s"""
         |pfam_scan.pl -fasta ${seqFile.unixPath} -dir ${Tool.pfamDir.unixPath}/db -outfile ${outFile.unixPath} -clan_overlap -as -cpu 16 -e_seq ${data.seqCutoff} -e_dom ${data.domainCutoff}
       """.stripMargin.conda()
    CommandData(workspaceDir, List(command))
  }

  def assemble(workspaceDir: File, resultDir: File) = {
    val outFile = Tool.getPfamOutFile(workspaceDir)
    val fqListFile = new File(workspaceDir, "fq.list")
    val configJson = Tool.getConfigFile(workspaceDir).str.toJson
    val fq1File = (configJson \ "fq1").as[String]
    val fq2File = (configJson \ "fq2").as[String]
    val gzDir = Tool.getGzDir(workspaceDir)
    val outDir = new File(workspaceDir, "out")
    val command =
      s"""
         |${Tool.assembleDir.unixPath}/SPAdes-3.13.1-Linux/bin/spades.py -t 12 -m 100 --careful --disable-gzip-output -1 ${fq1File.unixPath} -2 ${fq2File.unixPath} -o ${outDir.unixPath}
         |perl ${Tool.assembleDir.unixPath}/Assembly_V2.6/lib/comm_bin/assembly_stat.pl -r ${outDir.unixPath}/scaffolds.fasta -s MCB.spades.scafSeq
         |perl ${Tool.assembleDir.unixPath}/Assembly_V2.6/lib/comm_bin/WGS_uplod_Seq.pl MCB.spades.scafSeq > MCB.spades.fna
         |#perl ${Tool.assembleDir.unixPath}/Genome_pipline/codes/assemle-summary.pl MCB.spades.fna > MCB.spades.fna.stat
         |cp MCB.spades.fna ${resultDir}/assemble.fasta
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def predict(workspaceDir: File, resultDir: File) = {
    val configJson = Tool.getConfigFile(workspaceDir).str.toJson
    val data = FormTool.predictForm.bind(configJson).get
    val prefix = "predict"
    val emptyAnnoFile = new File(workspaceDir, "empty.anno.xls").createFileWhenNoExist
    val command =
      s"""
         |perl ${Tool.binPath.unixPath}/01.Gene-prediction/bin/gene-predict_v2.pl --SpeType B --SampleId ${prefix} --genemark --verbose -shape ${data.shape} --cpu 10  --run multi -outdir output ${Tool.getSeqFile(workspaceDir).unixPath}
         |cp ${workspaceDir.unixPath}/output/final/${prefix}.cds ${resultDir.unixPath}/${prefix}.cds.fa
         |cp ${workspaceDir.unixPath}/output/final/${prefix}.pep ${resultDir.unixPath}/${prefix}.pep.fa
         |cp ${workspaceDir.unixPath}/output/final/${prefix}.gff ${resultDir.unixPath}/
         |perl ${Tool.binPath.unixPath}/tgs/make_genbank_v3.4.pl --SpeType B ${workspaceDir.unixPath}/output/final/${prefix}.cds ${workspaceDir.unixPath}/output/final/${prefix}.pep  ${workspaceDir.unixPath}/output/final/${prefix}.gff ${emptyAnnoFile.unixPath} --outfile ${prefix}.gbk --outdir ./ --tRNA ${prefix}.tRNA.gff --rRNA ${prefix}.rRNA.gff --shape ${data.shape} --predict "GeneMarkS 4.6b"
         |cp ${prefix}.gbk ${resultDir.unixPath}/
             """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def anno(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.annoForm.bind(configJson).get
    val dataFile = Tool.getSeqFile(workspaceDir)
    val mergeCommand1 = s"perl ${Tool.annoDir.unixPath}/anno_st/mergeAnnotation.pl -fa ${dataFile.unixPath}"
    val keggDir = new File(resultDir, "KEGG")
    val profileFileName = data.dbKind match {
      case "prokaryote" => "prokaryote"
      case "eukaryote" => "eukaryote"
      case "all" => "profiles"
    }
    val threadNum=24
    val profileFile = new File(Tool.keggDir, s"db/${profileFileName}")
    val (keggCommand, keggMergeCommand) = if (data.annoMethods.contains("kegg")) {
      Utils.createDirectoryWhenNoExist(keggDir)
      val pathwayFile = new File(keggDir, "pathway.txt")
      val keggCommand =
        s"""
           |ruby ${Tool.keggDir.unixPath}/bin/kofamscan/exec_annotation -o CS6.kegg.txt ${dataFile.unixPath} -p ${profileFile.unixPath} --cpu ${threadNum}
           |perl ${Tool.keggDir.unixPath}/filter_kofam.pl CS6.kegg.txt ${Tool.keggDir.unixPath}/K.descript.txt ${Tool.keggDir.unixPath}/K.ko.map.txt ${Tool.keggDir.unixPath}/ko.layer.txt
           |cp pathway.txt ${pathwayFile.unixPath}
               """.stripMargin.conda()
      val keggMergeCommand = s"-kobas ${pathwayFile.unixPath}"
      (keggCommand, keggMergeCommand)
    } else ("", "")

    val (goCommand, goMergeCommand) = if (data.annoMethods.contains("go")) {
      val goDir = new File(resultDir, "GO")
      Utils.createDirectoryWhenNoExist(goDir)
      val goTxtFile = new File(goDir, "GO.list.txt")
      val goCommand =
        s"""
           |python ${Tool.binPath.unixPath}/eggnog-mapper/emapper.py -i ${dataFile.unixPath} --output eggNOG.m8.xls -m diamond --cpu ${threadNum}
           |grep -v \\# eggNOG.m8.xls.emapper.annotations |cut -f 1,6 |grep \\GO |sed -e 's/,/;/g' >${goTxtFile.unixPath}
           |python ${Tool.binPath.unixPath}/goatools-0.5.7/scripts/gene_ontology.py --level 1 --input ${goTxtFile.unixPath} --output ${new File(goDir, "level2.go.txt").unixPath}
           |perl   ${Tool.annoDir.unixPath}/anno_st/go-bar.pl -i ${new File(goDir, "level2.go.txt").unixPath} -o ${new File(goDir, "level2.go.txt.pdf").unixPath}
               """.stripMargin.conda("py2713")
      val goMergeCommand = s"-go ${goTxtFile.unixPath}"
      (goCommand, goMergeCommand)
    } else ("", "")
    val finalMergeCommand = s">${new File(resultDir, "annotation.table.xls").unixPath}"
    val mergeCommand = List(mergeCommand1, keggMergeCommand, goMergeCommand, finalMergeCommand).mkString(" ").conda()
    val commands = List(keggCommand, goCommand, mergeCommand)
    CommandData(workspaceDir, commands)
  }

  def ardb(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.ardbForm.bind(configJson).get
    val command =
      s"""
         |perl ${Tool.annoDir.unixPath}/4-13.ardb_anno.pl -e ${data.evalue}  ${Tool.getSeqFile(workspaceDir).unixPath} ${Tool.annoDir.unixPath}/ardbAnno1.0/ ./
         |cp ardb.anno.xls ${resultDir.unixPath}
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def cazy(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.cazyForm.bind(configJson).get
    val command =
      s"""
         |perl ${Tool.annoDir.unixPath}/4-10.cazy_anno.pl ${Tool.getSeqFile(workspaceDir).unixPath} data ${Tool.annoDir.unixPath}/CAZyme
         |cp data.anno.xls ${resultDir.unixPath}/cazy.anno.xls
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def vfdbResultDeal(workspaceDir: File, resultDir: File) = {
    val file = new File(resultDir, "vfdb.anno.xls")
    val lines = file.txtLines
    val newLines = lines.map { columns =>
      val newColumns = List(columns(5), columns(11)) ::: (columns.filter { x =>
        !List(columns(5), columns(11)).contains(x)
      })
      newColumns
    }
    newLines.toTxtFile(file)
  }

  def phiResultDeal(workspaceDir: File, resultDir: File) = {
    val file = new File(resultDir, "phi.anno.xls")
    val lines = file.txtLines
    val newLines = lines.map { columns =>
      val newColumns = List(columns(5), columns(11)) ::: (columns.filter { x =>
        !List(columns(5), columns(11)).contains(x)
      })
      newColumns
    }
    newLines.toTxtFile(file)
  }

  def tcdbResultDeal(workspaceDir: File, resultDir: File) = {
    val file = new File(resultDir, "tcdb.anno.xls")
    val lines = file.txtLines
    val newLines = lines.map { columns =>
      val newColumns = List(columns(5), columns(11)) ::: (columns.filter { x =>
        !List(columns(5), columns(11)).contains(x)
      })
      newColumns
    }
    newLines.toTxtFile(file)
  }

  def pfamResultDeal(workspaceDir: File, resultDir: File) = {
    val file = Tool.getPfamOutFile(workspaceDir)
    val str = "<seq id> <alignment start> <alignment end> <envelope start> <envelope end> <hmm acc> <hmm name> <type> <hmm start> <hmm end> <hmm length> <bit score> <E-value> <significance> <clan> <predicted_active_site_residues>"
    val r = "<([^<>]*)>".r
    val headers = r.findAllMatchIn(str).toList.map(_.group(1))
    val contentLines = file.lines().filter { line =>
      !line.startsWith("#")
    }.txtLines("\\s+")
    val newLines = headers :: contentLines
    newLines.notEmptyLines.toTxtFile(Tool.getPfamOutFile(resultDir))
  }

  def annoResultDeal(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.annoForm.bind(configJson).get
    if (data.annoMethods.contains("kegg")) {
      val keggDir = new File(resultDir, "KEGG")
      val keggFile = new File(keggDir, "pathway.txt")
      val cleanFile = new File(keggDir, "pathway.clean.txt")
      val lines = keggFile.txtLines
      val newLines = lines.filter(_.size == 2).filter(x => x.exists(y => y.contains("http"))).map { columns =>
        val newHead = columns(1).takeWhile(_ != '|')
        newHead :: columns.tail
      }
      newLines.toTxtFile(cleanFile)
    }
  }

  def cazyResultDeal(workspaceDir: File, resultDir: File) = {
    val file = new File(resultDir, "cazy.anno.xls")
    val lines = Utils.file2Lines(file)
    val headers = lines(0).split("\t")
    headers(1) = "Q-length"
    headers(3) = "S-length"
    lines(0) = headers.mkString("\t")
    Utils.lines2File(file, lines)
  }

}
